package com.lipaluma.field.validator.impl.string;
import java.lang.reflect.Field;
import java.util.List;

import com.lipaluma.annotations.validations.Validate;
import com.lipaluma.context.Context;
import com.lipaluma.field.validator.ValidationError;
import com.lipaluma.field.validator.Validator;
import com.lipaluma.field.validator.strategies.LengthStrategy;
import com.lipaluma.xml.validator.XmlLengthValidator;
import com.lipaluma.xml.validator.XmlValidator;

/**
 * Validator for String field that check the length of that String with different possible strategies :<br/>
 * <p>
 * The strategies are defined by the enum {@link LengthStrategy} : <br/>
 *  - <b>GREATER_THAN</b> : the length of the string value must be strictly greater than the given value.<br/>
 *  - <b>GREATER_THAN_OR_EQUALS</b> : the length of the string value must be greater than or equals to the given value.<br/>
 *  - <b>LESS_THAN</b> : the length of the string value must be strictly less than the given value.<br/>
 *  - <b>LESS_THAN_OR_EQUALS</b> : the length of the string value must be less than or equals to the given value.<br/>
 *  - <b>EQUALS</b> : the length of the string value must be equals to the given value. <b>The default one</b>.<br/>
 *  - <b>NOT_EQUALS</b> : the length of the string value must not be equals to the given value.<br/>
 *  
 * <p>
 * To initialize : 
 * <ul>
 * 	<li>
 * 	<u><b>By annotations :</b></u> Use {@link Validate} and define the length of the string with the 
 * <code>length</code> attribute.<br/>
 * The strategy may be defined by using the attribute <code>lengthStrategy</code>. By default, the Equals strategy is defined.
 * 	</li>
 * 	<li>
 * 	<u><b>By Xml :</b></u>
 * <ul>
 * <li>
 * To add the length validation, see the example below : <br/>
 * <code>
 * &lt;ToMap field="..."><br/>
 * <b>
 * &nbsp;&nbsp;&nbsp;&lt;length strategy="GREATER_THAN">10&lt;/length><br/>
 * </b>
 * &lt;/ToMap><br/>
 * </code>
 * In this example, we have choosen the GREATER_THAN strategy. The length will must be greater than 10.
 * The strategy attribute is optional, the default strategy is EQUALS.
 * </li>
 * </ul>
 * 
 * @see {@link  LengthStrategy}
 * @author Mario
 */
public class StringLengthValidator implements Validator {
	private int threshold;
	private LengthStrategy strategy;
	
	public StringLengthValidator() {}
	public StringLengthValidator(int threshold) {
		this(threshold, LengthStrategy.EQUALS);
	}
	public StringLengthValidator(int threshold, LengthStrategy strategy) {
		this.threshold = threshold;
		this.strategy = strategy;
	}
	
	public boolean init(Context context, Field field) {
		Validate annotation = field.getAnnotation(Validate.class);
		if(annotation == null || annotation.length() < 0)
			return false;
		this.threshold = annotation.length();
		this.strategy = annotation.lengthStrategy();
		return true;
	}

	public boolean init(Context context, Field field, XmlValidator xmlValidator) {
		XmlLengthValidator validator = (XmlLengthValidator) xmlValidator;
		this.threshold = validator.getValue();
		this.strategy = validator.getLengthStrategy() != null ? validator.getLengthStrategy() : LengthStrategy.EQUALS; 
		return true;
	}
	
	public boolean validate(Object value, List<ValidationError> errors) {
		if(!strategy.validate(this.threshold, value.toString().length())) {
			errors.add(new ValidationError("The length of "+value+" is not respecting strategy "+strategy+" with threshold "+threshold));
			return false;
		}
		return true;
	}

}
